from rest_framework import serializers
from .models import User
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
from rest_framework.exceptions import ValidationError

class UserModelSerializer(serializers.ModelSerializer):
    # 必须重写username字段
    '''
       username:由于映射了User表的Username，自己有规则，unique=True
       username字段自己的校验，会走unique，会去数据库查是否有这个用户，如果有，直接抛异常
       重写这个字段，不设置规则
   '''
    username = serializers.CharField()

    class Meta:
        model = User
        fields = ['username', 'password', 'id']
        extra_kwargs = {
            'username': {'write_only': True},
            'password': {'write_only': True},
            'id': {'read_only': True},
        }

    # 写全局钩子(校验用户名、密码，登录成功，签发token)
    def validate(self, attrs):
        # 取出用户名和密码
        username = attrs.get('username')
        password = attrs.get('password')
        # 校验用户名
        import re
        if re.match(r'^1[3-9][0-9]{9}$',username):
            user = User.objects.filter(mobile=username).first()
        elif re.match(r'^.+@.+',username):
            user = User.objects.filter(email=username).first()
        else:
            user = User.objects.filter(username=username).first()
        # 校验密码
        if user and user.check_password(password):
            # 用户名和密码都正确，签发token
            from rest_framework_jwt.views import obtain_jwt_token
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            self.context['username'] = user.username
            self.context['token'] = token
            self.context['user'] = user
            # self.instance = user  # 等价于上面

            return attrs
        else:
            raise ValidationError('用户名或密码错误')

class MobileLoginSerializer(serializers.ModelSerializer):
    # 重写mobile字段的原因 unique=True
    mobile = serializers.CharField()
    # 重写code,不是表中的字段，所有必须重写
    code = serializers.CharField()
    class Meta:
        model = User
        fields = ['mobile','code']
        # 用户校验和签发token

    def validate(self, attrs):
        '''
        1 校验code是否正确：从缓存中根据手机号获取code，比较

        2 根据手机号，拿到当前用户，
        3 根据用户，签发token
        3 把token放到序列化类的对象中
        '''

        user = self._get_user(attrs)
        token = self._get_token(user)
        # 上下文，是个字典
        self.context['token'] = token
        self.context['username'] = user.username

        return attrs

    def _get_user(self, attrs):  # 不是私有，但尽量只给内部用
        code = attrs.get('code')
        mobile = attrs.get('mobile')
        # 校验code
        cache_code = cache.get(settings.CACHE_SMS % mobile)
        if cache_code and code == cache_code:
            user = User.objects.filter(mobile=mobile).first()
            if user:
                return user
            else:
                raise ValidationError('用户名或密码错误')
        else:
            raise ValidationError('验证码错误')

    def _get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token


from django.core.cache import cache
from django.conf import settings


class RegisterUserSerializer(serializers.ModelSerializer):
    # code 不是User表的字段，必须重写
    code = serializers.CharField(max_length=4, min_length=4,write_only=True)

    class Meta:
        model = User
        fields = ['mobile', 'code', 'password', 'username']
        extra_kwargs = {'mobile': {'write_only': True},
                        'password': {'write_only': True}, 'username': {'read_only': True}}

    # 如果想让密码比较复杂，可以给密码写一个局部钩子，使用正则去匹配
    # 校验字段
    def validate(self, attrs):
        '''
        1 校验code是否正确
        2 把code从attrs中剔除
        3 使用手机号作为用户名，后期可以改
        '''
        code = attrs.get('code')
        mobile = attrs.get('mobile')
        # 校验code
        cache_code = cache.get(settings.CACHE_SMS % mobile)
        print(cache_code)
        if cache_code and code == cache_code:
            # 把code剔除，code不是User表的字段，不能用来保存
            attrs.pop('code')
            # 创造一个username
            attrs['username'] = mobile
        else:
            raise ValidationError({'detail': '验证码错误'})

        return attrs

    # 为什么要重写create? 因为密码是明文的，需要使用create_user创建用户
    def create(self, validated_data):

        user = User.objects.create_user(**validated_data)
        return user


